package com.xbongbong.process.operate;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.FieldPermissionEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasProcessTemplateEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasProcessTemplateNodeEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.model.PaasProcessTemplateModel;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.domain.entity.FormConfigEntity;
import com.xbongbong.pro.enums.workflow.TriggerEventTypeEnum;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.model.FormConfigModel;
import com.xbongbong.workflow.domain.entity.WorkflowEntity;
import com.xbongbong.workflow.domain.entity.WorkflowNodeEntity;
import com.xbongbong.workflow.enums.WorkflowNodeTypeEnum;
import com.xbongbong.workflow.model.WorkflowModel;
import com.xbongbong.workflow.model.WorkflowNodeModel;
import com.xbongbong.workflow.pojo.nodes.FormTriggerNode;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author 吴峰
 * @date 2021/06/23 9:47
 */

@Component
public class ProcessFieldHelp {

    private static final Logger LOG = LoggerFactory.getLogger(ProcessFieldHelp.class);

    @Resource
    private ProcessStartHelp processStartHelp;
    @Resource
    private PaasProcessTemplateModel paasProcessTemplateModel;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private WorkflowNodeModel workflowNodeModel;
    @Resource
    private WorkflowModel workflowModel;
    @Resource
    private FormConfigModel formConfigModel;

    /**
     * 根据流程的节点属性设置字段可见
     * @param paasFormEntityExt
     * @param explainMap
     * @throws XbbException
     */
    public void processSetVisible(PaasFormEntityExt paasFormEntityExt, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        processSetVisible(paasFormEntityExt.getIsProcessForm(), paasFormEntityExt.getCorpid(), paasFormEntityExt.getId(), paasFormEntityExt.getAppId(), explainMap);
    }



    /**
     * 根据流程的节点属性设置字段可见
     * @param isProcessForm
     * @param formId
     * @param appId
     * @param formDataSaveDTO
     * @param explainMap
     * @throws XbbException
     */

    public Map<String, FieldAttrEntity> importProcessSetVisible(Integer isProcessForm, Long formId, Long appId, FormDataAddDTO formDataSaveDTO, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        if (CollectionsUtil.isEmpty(formDataSaveDTO.getAttrList())) {
            return processSetVisible(isProcessForm, formId, appId, formDataSaveDTO, explainMap);
        }
        // 部分字段导入的时候，validateDataDTO的explainMap传的是剔除了无需导入的字段map，跳过无需导入字段的通用校验
        // saasSaveHelp.beforeSave(validateDataDTO);方法后面又把全部字段的explainMap赋值给validateDataDTO，防止后面要用其它字段解释
        Map<String, FieldAttrEntity> simpleExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        for (String s : formDataSaveDTO.getAttrList()) {
            FieldAttrEntity fieldAttrEntity = explainMap.get(s);
            if (Objects.nonNull(fieldAttrEntity)) {
                simpleExplainMap.put(s, fieldAttrEntity);
            }
        }
        // 流程设置可见
        processSetVisible(isProcessForm, formDataSaveDTO.getCorpid(), formId, appId, simpleExplainMap);
        // 获取严控下的流水号以及系统字段设置
        return simpleExplainMap;
    }
    /**
     * 根据流程的节点属性设置字段可见
     * @param isProcessForm
     * @param formId
     * @param appId
     * @param formDataSaveDTO
     * @param explainMap
     * @throws XbbException
     */

    public Map<String, FieldAttrEntity> processSetVisible(Integer isProcessForm, Long formId, Long appId, FormDataAddDTO formDataSaveDTO, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        // 流程设置可见
        processSetVisible(isProcessForm, formDataSaveDTO.getCorpid(), formId, appId, explainMap);
        // 获取严控下的流水号以及系统字段设置
        return explainMap;
    }

    public void processSetVisible(Integer isProcessForm, String corpid, Long formId, Long appId, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        if (Objects.equals(1, isProcessForm)) {
            Map<String, FieldPermissionEntityExt> fieldPermissionMap = new HashMap<>(explainMap.size());
            // 判断是否开启流程，进行字段的可见属性修改；
            if (commonHelp.isOpenWorkFlow(corpid)) {
                Map<String, Object> processTemplateParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                processTemplateParam.put(StringConstant.CORPID, corpid);
                processTemplateParam.put("formId", formId);
                processTemplateParam.put("del", DelEnum.NORMAL.getDel());
                processTemplateParam.put("appId", appId);
                processTemplateParam.put("enable", 1);
                processTemplateParam.put("usePermission", 1);
                processTemplateParam.put("currentVersion", 1);
                processTemplateParam.put("isApprove", 1);
                processTemplateParam.put("triggerEventTypeIn", Arrays.asList(TriggerEventTypeEnum.ONLY_ADD.getType(), TriggerEventTypeEnum.ADD_OR_UPDATE.getType()));
                processTemplateParam.put(ParameterConstant.COLUMNS, " enable, id ");
                processTemplateParam.put(ParameterConstant.ORDER_BY_STR, "priority asc");
                List<WorkflowEntity> workflowList = workflowModel.findEntitys(processTemplateParam);
                if (CollectionUtils.isNotEmpty(workflowList)) {
                    WorkflowNodeEntity workflowNodeEntity = workflowNodeModel.getByUId(workflowList.get(0).getId(), corpid, WorkflowNodeTypeEnum.START_NODE.getName());
                    FormTriggerNode formTriggerNode = JSON.parseObject(workflowNodeEntity.getConfigData(), FormTriggerNode.class);
                    if (Objects.nonNull(formTriggerNode)) {
                        fieldPermissionMap = formTriggerNode.getFieldPermission();
                    }
                }
            } else {
                List<PaasProcessTemplateEntityExt> templateList = processStartHelp.getProcessTemplateList(corpid, formId, appId);
                if (!Objects.equals(templateList.size(), 0)) {
                    PaasProcessTemplateEntityExt paasProcessTemplateEntityExt = templateList.get(0);
                    PaasProcessTemplateNodeEntityExt processTemplateNode = processStartHelp.getStartNode(corpid, formId, appId, paasProcessTemplateEntityExt);
                    List<FieldPermissionEntityExt> fieldPermissionList = processTemplateNode.getFieldPermissionList();
                    fieldPermissionMap = new HashMap<>(fieldPermissionList.size());
                    for (FieldPermissionEntityExt item : fieldPermissionList) {
                        String attr = item.getAttr();
                        if (StringUtil.isNotEmpty(item.getSubAttr())) {
                            attr = attr + StringConstant.POINT + item.getSubAttr();
                        }
                        fieldPermissionMap.put(attr, item);
                    }
                }
            }
            Iterator<String> iterator = explainMap.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                FieldAttrEntity fieldAttrEntity = explainMap.get(key);
                FieldPermissionEntityExt fieldPermissionEntityExt = fieldPermissionMap.get(key);
                if (Objects.nonNull(fieldPermissionEntityExt) && Objects.nonNull(fieldAttrEntity)) {
                    fieldAttrEntity.setVisible(fieldPermissionEntityExt.getVisible());
                    if (ExplainUtil.isSubForm(fieldAttrEntity.getFieldType())) {
                        List<? extends FieldAttrEntity> subFieldList = fieldAttrEntity.getSubForm().getItems();
                        Iterator<? extends FieldAttrEntity> iterator1 = subFieldList.iterator();
                        while (iterator1.hasNext()) {
                            FieldAttrEntity subField = iterator1.next();
                            fieldPermissionEntityExt = fieldPermissionMap.get(subField.getParentAttr() + StringConstant.POINT + subField.getAttr());
                            if (Objects.nonNull(fieldPermissionEntityExt)) {
                                subField.setVisible(fieldPermissionEntityExt.getVisible());
                            }
                        }
                        fieldAttrEntity.getSubForm().setItems(subFieldList);
                    }
                } else if (Objects.isNull(fieldPermissionEntityExt) && !Objects.isNull(fieldAttrEntity)) {
                    // 处理团队成员放出 回款单、付款单、应收款、付款计划、联系人、供应商联系人 负责人和协同人 字段后老数据
                    if (Objects.equals(fieldAttrEntity.getAttr(), "ownerId") || Objects.equals(fieldAttrEntity.getAttr(), "coUserId")) {
                        fieldAttrEntity.setVisible(BasicConstant.ONE);
                    }
                }
            }
        }
    }

    /**
     *  详情页是否允许快速编辑字段
     * com.xbongbong.saas.service.impl.MobileDetailServiceImpl#isEditable(java.lang.String, java.util.Map, com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt, java.lang.String, com.xbongbong.paas.pojo.dto.FormDataGetDTO)
     * @param explainMap 字段解释容器
     * @param appId
     * @param formId
     * @param flowStatus
     * @param attr 字段attr
     * @param handlerExplainDTO 操作人
     * @return 详情页是否允许快速编辑
     * @author long.rao
     * @date 2019-11-12 11:00
     */
    public Integer isEditable(String corpid, Map<String, FieldAttrEntity> explainMap, Long appId, Long formId, Integer flowStatus, String attr, HandlerExplainDTO handlerExplainDTO) {
        //int editable = 0 ;
        Boolean fieldCanEdit = false;
        FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
        if(fieldAttrEntity == null){
            return 0;
        }
        Integer editable = fieldAttrEntity.getEditable();
        try {
            fieldCanEdit = ExplainUtil.isEditableOfScope(fieldAttrEntity,handlerExplainDTO);
        } catch (XbbException e) {
            LOG.error("判断字段是否可编辑出错 attrCanEdit:");
            e.printStackTrace();
        }
        boolean isAdminOrBoss = handlerExplainDTO.getLoginUser().isAdminOrBoss();
        List<String> needApproveList = null;
        if (commonHelp.isOpenWorkFlow(corpid)) {
            //工作流漏写了
            String alias = RedisPrefixConstant.ALLOW_EDIT_AFTER_FINISHED;
            FormConfigEntity formConfigEntity = formConfigModel.getByConfig(alias, corpid, formId, handlerExplainDTO.getSaasMark(), handlerExplainDTO.getBusinessType());
            Integer allowEditAfterFinished = 0;
            if (Objects.nonNull(formConfigEntity)) {
                allowEditAfterFinished = Integer.valueOf(formConfigEntity.getConfigValue());
            }
            if (!isAdminOrBoss) {
                if (Objects.equals(flowStatus, FlowStatusEnum.PASS.getType()) && !Objects.equals(allowEditAfterFinished, 1)) {
                    // 非超管，如果流程开启了审批完成后不允许编辑，那么app详情页的快速编辑字段就不能编辑
                    return 0;
                }
            }
            Map<String, Object> processTemplateParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            processTemplateParam.put("corpid", corpid);
            processTemplateParam.put("appId", appId);
            processTemplateParam.put("formId", formId);
            processTemplateParam.put("del", 0);
            processTemplateParam.put("enable", 1);
            processTemplateParam.put("usePermission", 1);
            processTemplateParam.put("currentVersion", 1);
            processTemplateParam.put("isApprove", 1);
            processTemplateParam.put("triggerEventTypeIn", Arrays.asList(TriggerEventTypeEnum.ONLY_ADD.getType(), TriggerEventTypeEnum.ADD_OR_UPDATE.getType()));
            processTemplateParam.put(ParameterConstant.COLUMNS, " enable, id ");
            processTemplateParam.put(ParameterConstant.ORDER_BY_STR, "priority asc");
            List<WorkflowEntity> workflowList = workflowModel.findEntitys(processTemplateParam);
            if (CollectionUtils.isNotEmpty(workflowList)) {
                WorkflowNodeEntity workflowNodeEntity = workflowNodeModel.getByUId(workflowList.get(0).getId(), corpid, WorkflowNodeTypeEnum.START_NODE.getName());
                if (Objects.nonNull(workflowNodeEntity)) {
                    FormTriggerNode formTriggerNode = JSON.parseObject(workflowNodeEntity.getConfigData(), FormTriggerNode.class);
                    if (Objects.nonNull(formTriggerNode)) {
                        needApproveList = formTriggerNode.getNeedApproveFields();
                    }
                }
            }
        } else {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", corpid);
            params.put("appId", appId);
            params.put("formId", formId);
            params.put("del", 0);
            params.put("enable", 1);
            params.put(ParameterConstant.COLUMNS, "need_approve_fields,allow_edit_after_finished");
            List<PaasProcessTemplateEntityExt> templateList = paasProcessTemplateModel.list(params);
            if (CollectionUtils.isNotEmpty(templateList)) {
                PaasProcessTemplateEntityExt paasProcessTemplateEntityExt = templateList.get(0);
                if (!isAdminOrBoss) {
                    Integer editAfterFinished = paasProcessTemplateEntityExt.getAllowEditAfterFinished();
                    if (Objects.equals(flowStatus, FlowStatusEnum.PASS.getType()) && !Objects.equals(editAfterFinished, 1)) {
                        // 非超管，如果流程开启了审批完成后不允许编辑，那么app详情页的快速编辑字段就不能编辑
                        return 0;
                    }
                }
                if (StringUtil.isNotEmpty(paasProcessTemplateEntityExt.getNeedApproveFields())) {
                    needApproveList = JSONArray.parseArray(paasProcessTemplateEntityExt.getNeedApproveFields(), String.class);
                }
            }
        }

        if ((explainMap.containsKey(attr) && Objects.equals(editable, 1) || fieldCanEdit ) && (needApproveList == null || !needApproveList.contains(attr))) {

        } else {
            // 字段如果不能编辑，或者流程里的它是需审批字段，那么app详情页的快速编辑字段就不能编辑
            editable = 0;
        }
        return editable;
    }
}
